
/*
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: GPL-3.0+
 * License-Filename: LICENSE
 * Copyright tuxsee authors
 */

/* generate c source from this using the flex lexer tool */

/*
 * this lexer is designed to be as easy as possible,
 * because all params are strings between "" there is
 * no additional lexing for numbers and identifiers.
 * This makes the tys graph language extra easy to parse.
 * toedoe: rewrite in manual lexer, needs less space.
 */

%{

#include "config.h"

#include <stdio.h>
#include <string.h>

#include "splay-tree.h"
#include "main.h"
#include "parse.h"
#include "uniqstring.h"

/* fread() with 128kb at once is fastest on Linux */
#define YY_READ_BUF_SIZE (128*1024)

/* limit max length of input string to avoid crashes */
#define MAXSTRING 22*1024

%}

	/* for lint purists according to flex manual */
%option nounput

	/* suppress gcc warning input() defined but not used */
%option noinput

	/* do not use call to fileno() */
%option noread

	/* input does not come from a tty. */
%option never-interactive

	/* no yywrap() at end of file */
%option noyywrap

	/* 8-bits scanner */
%option 8bit

	/* generate line number */
%option yylineno

ISTR	[^\\\"]|\\.|\\\n
STR	\"({ISTR}*)\"
CCS	\/\*[^\*]*\*+([^\*\/][^\*]*\*+)*\/
CCS0		\/\*
CCS1		\*\/
CCE	\/\/[^\n]*

%%

"#".* { /* dot comment line */ }

{CCS} { /* c-comment style */ /* lexer does update yylineno */ }
{CCS0} { /* start of c comment but no end of c comment */ fprintf(stderr,"%s(): unterminated start of c comment at line %d\n",__FUNCTION__,tyslex_lineno()); fflush(stderr); return (TYS_CERROR); }
{CCS1} { /* end of c comment but no start of c comment */ fprintf(stderr,"%s(): end of c comment at line %d but no start\n",__FUNCTION__,tyslex_lineno()); fflush(stderr); return (TYS_CERROR); }

{CCE} { /* c++ comment style */ /* lexer does update yylineno */ }

"DIGRAPH" { return (TYS_DIGRAPH); }
"GRAPH" { return (TYS_GRAPH); }
"STRICT" { return (TYS_STRICT); }

"arrows" { return (TYS_ARROWS); }
"color" { return (TYS_COLOR); }
"digraph" { return (TYS_DIGRAPH); }
"edge" { return (TYS_EDGE); }
"folded" { return (TYS_FOLDED); }
"fontname" { return (TYS_FONTNAME); }
"fontsize" { return (TYS_FONTSIZE); }
"graph" { return (TYS_GRAPH); }
"label" { return (TYS_LABEL); }
"node" { return (TYS_NODE); }
"settings" { return (TYS_SETTINGS); }
"shape" { return (TYS_SHAPE); }
"strict" { return (TYS_STRICT); }
"style" { return (TYS_STYLE); }
"subgraph" { return (TYS_SUBGRAPH); }
"textcolor" { return (TYS_TEXTCOLOR); }
"textslant" { return (TYS_TEXTSLANT); }
"textweight" { return (TYS_TEXTWEIGHT); }
"thickness" { return (TYS_THICKNESS); }
"url" { return (TYS_URL); }
"void" { return (TYS_VOID); }


"\xef\xbb\xbf" { /* this is dot specific */ return (TYS_UTF8BOM); }

[\f ]+ { /* skip form feed chars and spaces */ }
[\t] { /* skip tabs */ }
[\n] { /* skip new line */ /* lexer does update yylineno */ }
[\r] { /* skip carriage return */ }

{STR} {
	/* string between "" is limited to MAXSTRING chars silently and rest of yytext is skipped */
	char *p = NULL;
	char c = 0;
	int i = 0;
	char buf[MAXSTRING];
	/* zero the " at the end of the string in yytext */
	yytext[strlen(yytext)-1] = '\0';
	p = yytext;
	/* skip the first " of the string in yytext */
	p = p + 1;
	i = 0;
	c = 0;
	memset (buf,0,MAXSTRING);
	while (*p)
	{
		/* check for esc char \ */
		if (*p == '\\') {
			/* skip the \ char */
			p = (p + 1);
			if (*p == 0) {
				/* hit end-of-file */
				break;
			}
			/* check for new line */
			if (*p == 'n') {
				c = '\n';
			} else if (*p == '"') {
				/* \" is seen as " */
				c = '"';
			} else {
				/* other \ char put literal in buffer */
				buf[i] = '\\';
				i = (i + 1);
				if (i >= (MAXSTRING -1)) {
					/* buffer is full */
					break;
				}
				c = *p;
			}
		} else {
			/* regular char and lexer does update yylineno at \n */
			c = *p;
		}
		/* put char in buffer */
		buf[i] = c;
		if (i >= (MAXSTRING -1)) {
			/* buffer is full */
			break;
		}
		/* to next pos in buffer */
		i = i + 1;
		/* now to next char in yytext */
		p = p + 1;
	}
	/* check for "" string */
	if (strlen(buf) == 0) {
		laststring = (char *)"";
	} else {
		laststring = uniqstring(buf);
	}
	return (TYS_STRING);
	}


"{" { return ('{'); }
"}" { return ('}'); }
"(" { return ('('); }
")" { return (')'); }
"=" { return ('='); }
"," { return (','); }
";" { return (';'); }

. { /* something else returned as token code */ return ((int)yytext[0]); }

%%

/* start lexer */
void tyslexinit (FILE *f, int tysdebug)
{
 yyin = f;
 yy_flex_debug = tysdebug;
 return;
}

/* clear lexer */
void tyslexreset (void)
{
 yylex_destroy ();
 yy_flex_debug = 0;
 return;
}

/* get current line number */
int tyslex_lineno (void)
{
 return (yylineno);
}

/* End */
